ext.define('extension.placeholders', function() {

var utils = extension.utils;
var messages = extension.messages;
var filters = extension.filters;
var mutations = extension.mutations;
var preferences = extension.preferences;
var place_holders = {};

function updateBoundingBox(records, observer) {
    var info = getPlaceholderByObserver(observer);
    if (info)
        utils.copyBoundingBox(records[0].target, info.container);
}

function createPlaceholder(id,  element) {
    if (place_holders[id])
        return place_holders[id];

    var container = utils.createElementPlaceholder(element, {
        panel: preferences.get('placeholder').panel,
        panelclick: preferences.get('panelclick')
    });
    container.className = 'flc-panel';
    return place_holders[id] = {
        key: id,
        wmode: false,
        container: container,
        observer: new window.MutationObserver(updateBoundingBox)
    };
}

function getPlaceholderById(id) {
    return place_holders[id];
}

function getPlaceholderByChild(child) {
    var placeholders = place_holders;
    for (var k in placeholders) {
        var container = placeholders[k].container;
        if (container === child || container.contains(child))
            return placeholders[k];
    }
}

function getPlaceholderByObserver(observer) {
    var placeholders = place_holders;
    for (var k in placeholders) {
        if (observer === placeholders[k].observer)
            return placeholders[k];
    }
}

function insertPlaceholder(info, element) {
    var container = info.container;
    if (element.nextSibling && element.nextSibling !== container)
        element.parentNode.insertBefore(container, element.nextSibling);
    else
        element.parentNode.appendChild(container);
    info.observer.observe(element,
        {'attributes': true, 'attributeFilter': ['style', 'width', 'height']});
}

function destroyPlaceholder(id) {
    return delete place_holders[id];
}

function removePlaceholder(id, element) {
    var info = getPlaceholderById(id);
    if (info) {
        var container = info.container;
        if (container.parentNode) {
            if (container.contains(element))
                releaseElement(info, element);
            container.parentNode.removeChild(container);
        }
        info.observer.disconnect();
    }
}

function captureElement(info, element) {
    mutations.disconnect();
    info.wmode = utils.setPluginParam(element, '/opaque|transparent/', 'wmode', 'opaque');
    info.container.appendChild(element);
    mutations.observe();
}

function releaseElement(info, element) {
    mutations.disconnect();
    if (info.wmode) {
        utils.removePluginParam(element, 'wmode');
        info.wmode = false;
    }
    var container = info.container;
    container.parentNode.insertBefore(element, container);
    mutations.observe();
}

function setPlaceholderTitle(info, element) {
    if (preferences.get('paneltooltip'))
        info.container.title = utils.getPluginSRC(element);
    else if (preferences.get('panelclick'))
        info.container.title = 'Click to load Flash content';
}

function removePlaceholderTitle(info) {
    info.container.removeAttribute('title');
}

function onPlaceholderClicked(event) {
    var info = getPlaceholderByChild(event.target);
    if (!info)
        return;

    var metadata = filters.search(info.key);
    if (!metadata)
        return;

    event.preventDefault();
    event.stopPropagation();

    if (event.target === info.container) {
        if (!preferences.get('panelclick'))
            return;
        if (!info.container.contains(metadata.element)) {
            if (preferences.get('toolbar')) {
                info.container.classList.add('flc-trans');
                info.toolbar = utils.createPlaceholderToolbar(info.container, {
                    toolbar: preferences.get('placeholder').toolbar
                });
                info.toolbar.className = 'flc-toolbar';
                captureElement(info, metadata.element);
                removePlaceholderTitle(info);
            }
            else
                info.container.style.setProperty('display', 'none', 'important');
            messages.send('unblock', metadata);
        }
    }
    else if (event.target === info.toolbar) {
        if (info.container.contains(metadata.element)) {
            undoElementCapture(info, metadata.element);
            setPlaceholderTitle(info, metadata.element);
            messages.send('block', metadata);
        }
    }
}

function undoElementCapture(info, element) {
    releaseElement(info, element);
    var container = info.container;
    container.textContent = '';
    container.classList.remove('flc-trans');
}

function onCapture(metadata) {
    var element = metadata.element;
    var info = createPlaceholder(metadata.id, metadata.element);
    var container = info.container;

    container.style.setProperty('display', metadata.flags & 2 ?
        'block' : 'none', 'important');
    setPlaceholderTitle(info, element);

    if (container.contains(element)) {
        undoElementCapture(info, element);
        insertPlaceholder(info, element);
        return;
    }

    insertPlaceholder(info, element);
}

function onCancel(metadata) {
    removePlaceholder(metadata.id, metadata.element);
    destroyPlaceholder(metadata.id);
}

return {
    bind: function() {
        document.addEventListener('click', onPlaceholderClicked, true);
        messages.listen({
            'restrict': onCapture,
            'allow': onCancel,
            'cancel': onCancel
        });
    }
};

});
